package app

import (
	"bytes"
	"encoding/base64"
	"errors"
	"fmt"
	"github.com/go-resty/resty/v2"
	"log/slog"
	"npm/utils"
	"os"
	"path/filepath"
	"strings"
	"sync"
)

type Upload struct {
	dir string
}

func UploadRun(dir string) error {
	up := Upload{dir: dir}
	return up.Start()
}

func (up *Upload) Start() error {

	files, fErr := up.getFiles()
	if fErr != nil {
		return fErr
	}

	var wg sync.WaitGroup
	var chQueue = make(chan struct{}, utils.Conf.Nexus.Threads)
	for _, file := range files {
		chQueue <- struct{}{}
		wg.Add(1)
		err := up.upload(file, &wg, chQueue)
		if err != nil {
			slog.Error("文件上传 ERROR", "file", filepath.Base(file), "error", err)
			continue
		}

		slog.Info("文件上传 SUCCESS", "file", filepath.Base(file))
	}

	wg.Wait()

	return nil
}

func (up *Upload) upload(file string, wg *sync.WaitGroup, ch chan struct{}) error {
	defer func() {
		<-ch
		wg.Done()
	}()

	fileBytes, readErr := os.ReadFile(file)
	if readErr != nil {
		return readErr
	}

	filename := filepath.Base(file)
	authInfo := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", utils.Conf.Nexus.Username, utils.Conf.Nexus.Password)))
	host := utils.Conf.Nexus.Host
	if strings.HasSuffix(host, "/") {
		host = host[:len(host)-1]
	}
	apiUrl := fmt.Sprintf("%s/service/rest/v1/components?repository=%s", utils.Conf.Nexus.Host, utils.Conf.Nexus.Repository)
	client := resty.New()
	client.SetHeader("Content-Type", "multipart/form-data")
	client.SetHeader("Authorization", fmt.Sprintf("Basic %s", authInfo))
	resp, err := client.R().SetFileReader("npm.asset", filename, bytes.NewReader(fileBytes)).Post(apiUrl)
	if err != nil {
		return err
	}

	if resp.StatusCode() != 204 {
		return errors.New(string(resp.Body()))
	}

	return nil
}

func (up *Upload) getFiles() ([]string, error) {
	var files []string
	err := filepath.Walk(up.dir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		if info.IsDir() || !strings.Contains(info.Name(), ".tgz") {
			return nil
		}

		files = append(files, path)
		return nil
	})

	if err != nil {
		return nil, fmt.Errorf("遍历目录时出错: %v", err)
	}

	return files, nil
}
